home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Communication
/
NewsBase
/
Source
/
IItemHeaderBrowser.m
< prev
next >
Wrap
Text File
|
1993-01-12
|
12KB
|
417 lines
/*$Copyright:
* Copyright (C) 1992.5.22. Recruit Co.,Ltd.
* Institute for Supercomputing Research
* All rights reserved.
* NewsBase by ISR, Kazuto MIYAI, Gary ARAKAKI, Katsunori SUZUKI, Kok-meng Lue
*
* You may freely copy, distribute and reuse the code in this program under
* following conditions.
* - to include this notice in the source code, if it is to be distributed
* with source code.
* - to add the file named "COPYING" within the code, which shall include
* GNU GENERAL PUBLIC LICENSE(*).
* - to display an acknowledgement in binary code as follows: "This product
* includes software developed by Recruit Co.,Ltd., ISR."
* - to display a notice which shall state that the users may freely copy,
* distribute and reuse the code in this program under GNU GENERAL PUBLIC
* LICENSE(*)
* - to indicate the way to access the copy of GNU GENERAL PUBLIC LICENSE(*)
*
* (*)GNU GENERAL PUBLIC LICENSE is stored in the file named COPYING
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
$*/
#import <appkit/appkit.h>
#import <mach/mach_init.h>
#import <string.h>
#import <defaults/defaults.h>
#import <dpsclient/event.h>
#import <libc.h>
#import "IItemHeaderBrowser.h"
#import "INXBrowserCellWithLinkedObject.h"
#import "IUifNode.h"
#import "IOrderedListD.h"
#import "InfoD.h"
#import "INewsGroupTreeControl.h"
#import "INewsgroupInfoD.h"
#import "ITreeNodeD.h"
#import "ITreeBrowserMatrix.h"
#import "errdebug.h"
#import "data_types.h"
#import "Localization.h"
#define MAX_NO_OF_TOKENS 256
#define MAXVISIBLECOL 2
#define MINCOLWIDTH 160
extern id currentNewsGroup;
@implementation IItemHeaderBrowser
- initFrame:(NXRect *)frameRect
{
[super initFrame:frameRect];
[self setMinColumnWidth:MINCOLWIDTH];
[self setMaxVisibleColumns:MAXVISIBLECOL];
[self setAction:@selector(singleClickLeafPreHandler:)];
[self setDoubleAction:@selector(doubleClickLeafPreHandler:)];
[self acceptArrowKeys:YES andSendActionMessages:NO];
return self;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- loadColumnZero
{
// make self first responder when loading column and column has
// any cells. if self(browser) has no column, then refuse to get
// first responder. data group browser might get first responder.
[super loadColumnZero];
if ([[[self matrixInColumn:0] cellList] count] > 0) {
[window makeFirstResponder:self];
}
return self;
}
/*
The target object and action message of itemheader is IItemHeaderBrowser
and articleHandler. I.e., articleHandler is called when a article is
selected.
*/
- (void)singleClickLeafPreHandler:sender
{
ITreeBrowserMatrix *lastColumnMatrix;
int keyFlag;
lastColumnMatrix = [self matrixInColumn:[self lastColumn]];
if (((keyFlag=(int)[lastColumnMatrix flagsOfLastEvent]) & NX_COMMANDMASK)
&& (keyFlag & NX_CONTROLMASK)) {
// 'command' + 'control' click
// post cancel article
if (NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Are you sure to cancel the article?"),
LoStr("NO"),LoStr("YES"),NULL) == 0) {
[lastColumnMatrix resetFlagsOfLastEvent];
[self cancelArticle];
return;
} else {
/* Cancel is clicked */
return;
}
}
if (strcmp(NXGetDefaultValue(OWNER, ARTICLESELECT),SINGLECLICK)==0) {
[self leafPreHandler:sender];
return;
} else {
// lastColumnMatrix = [self matrixInColumn:[self lastColumn]];
if (keyFlag & NX_CONTROLMASK) {
DBG(1,fprintf(stderr,"-- IItemHeaderBrowser:singleClick"));
// don't have to reset flags in matrix because "leafPreHander:"
// will do it in next statement.
[self leafPreHandler:sender];
return;
}
return;
}
}
- (void)doubleClickLeafPreHandler:sender
{
if (strcmp(NXGetDefaultValue(OWNER, ARTICLESELECT),DOUBLECLICK)==0) {
[self leafPreHandler:sender];
return;
} else {
return;
}
}
- (void)leafHandler:sender
{
id selectedCell;
id articleItem;
id node;
[window makeFirstResponder:self]; // set first responder to self
selectedCell = [[self matrixInColumn:[self lastColumn]] selectedCell];
if ([selectedCell isLeaf]) {
node = [selectedCell node];
if ((articleItem = [iIOmodule itemOf:node])==nil) {
return;
}
/* set no active to cell */
if (([node active]==YES) && ([iIOmodule toggleActive:node]==YES)) {
[selectedCell setActive:NO];
[node setActive:NO];
}
[[self matrixInColumn:[self lastColumn]] display];
return;
}
return;
}
- directoryHandler:node
{
[window makeFirstResponder:self]; // set first responder to self
return [iIOmodule itemHeadersOf:node];
}
- keyDown:(NXEvent *)theEvent
{
unsigned int ch;
id selectedCell;
DBG(1,fprintf(stderr," keydown"));
selectedCell = [[self matrixInColumn:[self selectedColumn]] selectedCell];
if ((ch=(theEvent->data).key.charCode) == NX_CR) {
// "Return" key pressed
DBG(1,fprintf(stderr," NX_CR"));
// click selected cell
if ([selectedCell isLeaf] ==YES) {
[self leafHandler:self];
}
return self;
}
if (ch == 0x20 || ch == 0x80) {
// 0x20 : space
// 0x80 : alt+space
if ([self selectedColumn] == -1) {
// no cell is selected so select first one
[[self matrixInColumn:0] selectCellAt:0 :0];
}
selectedCell = [[self matrixInColumn:[self selectedColumn]]
selectedCell];
if ((theEvent->flags & NX_SHIFTMASK) == NO) {
// select next cell
if (theEvent->flags & NX_ALTERNATEMASK) {
// alternate key is down, select next cell
selectedCell = [self selectNextCell:selectedCell];
} else {
// start loop for selecting next *active* *leaf* cell
do {
if ([selectedCell isLeaf] == YES
&& [[selectedCell node] active] == YES) {
break;
}
selectedCell = [self selectNextCell:selectedCell];
} while (selectedCell != NULL);
}
} else {
// select prev cell
DBG(1,fprintf(stderr,"--- space+shift\n"));
[self selectPrevCell:selectedCell];
}
if (selectedCell != NULL) {
if ((theEvent->flags & NX_ALTERNATEMASK)==NO
&& (theEvent->flags & NX_SHIFTMASK)==NO) {
// cell is selected and alt key is not down, click cell
[self leafHandler:self];
}
return self;
} else {
// no more cells, so beep
return ([super keyDown:theEvent]);
}
}
// handle arrow keys in super class
return ([super keyDown:theEvent]);
}
- selectNextCell:nowselectedCell
{
return([self _selectCell:nowselectedCell direct:(DirectFlag)FORWARD]);
}
- selectPrevCell:nowselectedCell
{
return([self _selectCell:nowselectedCell direct:(DirectFlag)BACKWARD]);
}
- _selectCell:nowselectedCell direct:(DirectFlag)dflag
{
unsigned int cellIndex;
id selectedColumnMatrix;
id rightColumnMatrix, leftColumnMatrix;
int trow, tcol; // can not use cellList???
int tcellIndex;
// cellList has old information and sometimes it points cell which
// is alread deleted
selectedColumnMatrix = [self matrixInColumn:[self selectedColumn]];
if ([nowselectedCell isLeaf] == YES) {
// no right column
cellIndex = [[selectedColumnMatrix cellList] indexOf:nowselectedCell];
[selectedColumnMatrix getNumRows:&trow numCols:&tcol];
// check if selectedCell is bottom(for FORWARD) or top(for BACKWORD)
if ((dflag == FORWARD && cellIndex < (trow -1))
|| (dflag == BACKWARD && cellIndex != 0)) {
// select next cell
if (dflag == FORWARD) {
tcellIndex = cellIndex + 1;
} else {
tcellIndex = cellIndex - 1;
}
[selectedColumnMatrix selectCellAt:tcellIndex :0];
[self scrollToCellAt:tcellIndex matrix:selectedColumnMatrix];
} else {
// this cell is bottom or top
if ((leftColumnMatrix=[self matrixInColumn:
([self selectedColumn] -1)]) != nil) {
// select next cell in left column
cellIndex = [[leftColumnMatrix cellList]
indexOf:[leftColumnMatrix selectedCell]];
[leftColumnMatrix getNumRows:&trow numCols:&tcol];
if ((dflag == FORWARD && cellIndex < (trow -1))
|| (dflag == BACKWARD && cellIndex != 0)) {
if (dflag == FORWARD) {
tcellIndex = cellIndex + 1;
} else {
tcellIndex = cellIndex - 1;
}
[leftColumnMatrix selectCellAt:tcellIndex :0];
[self setLastColumn:0];
[self scrollToCellAt:tcellIndex matrix:leftColumnMatrix];
} else {
// left cell is last one
[self setLastColumn:0];
return NULL;
}
} else {
// no left column
// this cell is really end
return NULL;
}
}
} else {
// there is right column, but no cell is selected
// select first cell in right column
[selectedColumnMatrix lockFocus];
[selectedColumnMatrix sendAction];
[selectedColumnMatrix unlockFocus];
rightColumnMatrix=[self matrixInColumn:([self selectedColumn] +1)];
if (dflag == FORWARD) {
[rightColumnMatrix selectCellAt:0 :0];
} else {
[rightColumnMatrix selectCellAt:
([rightColumnMatrix cellCount]-1) :0];
}
}
// return id of selectedCell
return ([[self matrixInColumn:[self selectedColumn]] selectedCell]);
}
- scrollToCellAt:(int)row matrix:matrix
{
NXRect matrixRect, cellRect;
id contView; // clipView
id scrollView; // scollView of a column for NXBrowser
NXRect contRect;
NXRect scrollerRect;
NXCoord cell_y, cont_y;
contView = [matrix superview];
scrollView = [[matrix superview] superview];
[matrix getFrame:&matrixRect];
[matrix getCellFrame:&cellRect at:row :0];
[contView getFrame:&contRect];
cell_y = cellRect.origin.y + cellRect.size.height;
cont_y = contRect.size.height - cellRect.size.height * 3;
// 3 cells are always shown after cell in (int)row
if (cont_y < cell_y) {
contRect.origin.y = cell_y - cont_y;
}
[[scrollView vertScroller] getFrame:&scrollerRect];
contRect.origin.x = 0.0;
[contView rawScroll:&(contRect.origin)];
[scrollView reflectScroll:contView];
return (self);
}
- cancelArticle
{
id selectedCell;
id node;
id header;
const char *messageID;
char *fromValue;
char buf[256], *user_name;
char *mailAddress;
selectedCell = [[self matrixInColumn:[self lastColumn]] selectedCell];
node = [selectedCell node];
if ((header=[[node linkedData] dataForKey:HEADER_INFO]) == nil) {
return (nil);
}
if ((fromValue=(char *)[header infoForKey:FROM]) == NULL) {
return (nil);
}
// check authentication
sscanf(fromValue, "%256[^@]", buf);
DBG(1,fprintf(stderr," buf = %s\n", buf));
if ((user_name=getenv("USER")) == NULL) {
return (nil);
}
if (strcmp(user_name,buf)!=0) {
NXRunAlertPanel(LoStr("NewsBase"),LoStr("From: field value not matched. Can not cancel"),NULL,NULL,NULL);
return (nil);
}
if ((messageID = (const char *)[header infoForKey:MESSAGE_ID]) == NULL) {
return (nil);
}
if (NXGetDefaultValue(OWNER,FROM) != NULL) {
mailAddress = NXCopyStringBuffer(NXGetDefaultValue(OWNER,FROM));
} else {
// set default value
mailAddress = [self getMailAddress];
}
[iIOmodule cancelArticleMessageID:messageID from:mailAddress];
free(mailAddress);
return self;
}
- (char *)getMailAddress
{
char *mail_address;
char *user_name, machine_name[256], domain_name[257];
user_name = NXCopyStringBufferFromZone(getenv("USER"),[self zone]);
gethostname(machine_name,sizeof(machine_name));
getdomainname(domain_name + 1, sizeof(domain_name) - 1);
domain_name[sizeof(domain_name) - 1] = '\0';
if (domain_name[1] != '\0') {
domain_name[0] = '.';
} else {
domain_name[0] = '\0';
}
mail_address = (char *)NXZoneMalloc([self zone],
strlen(user_name)+strlen(machine_name)+strlen(domain_name)+3);
(void)sprintf(mail_address,"%s@%s%s",user_name,machine_name,
domain_name);
return mail_address;
}
@end